package xyz.tanxiao.links.core.mapping;

import cn.hutool.crypto.SecureUtil;
import org.springframework.stereotype.Component;

import java.util.*;

/**
 * 长链接哈希压缩规则
 *
 * @author 万成波
 * @email 2300064869@qq.com
 * @createTime 2023-06-10 15:18:03 星期六
 */
@Component
public class LongLinkMd5MappingKey implements LongLinkMappingKey<String> {

	private static final String BASE62_STRING = "1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";

	private static final char[] BASE62_CHARACTERS = BASE62_STRING.toCharArray();


	/**
	 * 长链接映射Key生成方法
	 *
	 * @param longLink 原始长链接
	 * @return 长链接映射Key
	 */
	@Override
	public List<String> toMappingKey(String longLink) {
		return generateMultipleMappingKey(longLink, UUID.randomUUID().toString());
	}


	/**
	 * 生成长链接映射Key，每次批量生成 4 个。
	 *
	 * @param longLink 原始长链接
	 * @param uniqueValue 其他唯一混淆字符
	 * @return 长链接映射Key
	 */
	public static List<String> generateMultipleMappingKey(String longLink, String uniqueValue) {
		StringBuilder keyStr = new StringBuilder();
		Set<String> mappingKeys = new HashSet<>(4);
		// 对原始长链接进行编码
		String encodeLink = SecureUtil.md5().digestHex(longLink + uniqueValue);

		// 每次生成 4 个mappingKey
		for (int i = 0; i < 4; i++) {
			String mappingKey = encodeLink.substring(i * 8, i * 8 + 8);
			// 将该字符串转换为十六进制，然后和 0x3FFFFFFF 进行与运算，获得一个30位的二进制数。
			long align = 0x3FFFFFFF & Long.parseLong(mappingKey, 16);
			// 每一次循环都将生成 1 位字符串，共生成 6 位长度的mappingKey。
			for (int j = 0; j < 6; j++) {
				// 获取数组下标 0 - 61
				long index = 0x0000003D & align;
				keyStr.append(BASE62_CHARACTERS[(int) index]);
				align = align >> 5;
			}
			mappingKeys.add(keyStr.toString());
			keyStr.setLength(0);
		}
		return new ArrayList<>(mappingKeys);
	}

}